/**
  ******************************************************************************
  * @file
  * @brief
  * @author taoye
  * @version V1.0.0
  * @date 2021/01/01
  ******************************************************************************
  */


/* Includes ------------------------------------------------------------------*/
#include "drv_f4_gpioexit.h"
/* Private defines -----------------------------------------------------------*/

/* Private Struct  -----------------------------------------------------------*/


/* Private enum    -----------------------------------------------------------*/


/* Private Variable  ---------------------------------------------------------*/
//Pointer
static uint8_t exit_group[] = {
    EXTI_PortSourceGPIOA,      
    EXTI_PortSourceGPIOB,   
    EXTI_PortSourceGPIOC,      
    EXTI_PortSourceGPIOD,     
    EXTI_PortSourceGPIOE,       
    EXTI_PortSourceGPIOF,     
    EXTI_PortSourceGPIOG,   
};

static uint32_t exit_gpio[]={
    EXTI_PinSource0,           
    EXTI_PinSource1,          
    EXTI_PinSource2,         
    EXTI_PinSource3,        
    EXTI_PinSource4,          
    EXTI_PinSource5,          
    EXTI_PinSource6,           
    EXTI_PinSource7,        
    EXTI_PinSource8,          
    EXTI_PinSource9,         
    EXTI_PinSource10,       
    EXTI_PinSource11,          
    EXTI_PinSource12,          
    EXTI_PinSource13,         
    EXTI_PinSource14,         
    EXTI_PinSource15,     
};       

static uint32_t exit_line[]={
    EXTI_Line0,  
    EXTI_Line1, 
    EXTI_Line2,     
    EXTI_Line3,     
    EXTI_Line4,       
    EXTI_Line5,     
    EXTI_Line6,     
    EXTI_Line7,      
    EXTI_Line8,       
    EXTI_Line9,       
    EXTI_Line10,      
    EXTI_Line11,     
    EXTI_Line12,    
    EXTI_Line13,      
    EXTI_Line14,     
    EXTI_Line15,     
};

static uint8_t exit_irqn[] = {
    EXTI0_IRQn,             
    EXTI1_IRQn,              
    EXTI2_IRQn,              
    EXTI3_IRQn,               
    EXTI4_IRQn,                  
    EXTI9_5_IRQn,
    EXTI15_10_IRQn, 
};

static void    (*callback[16]) (void);
//Array

//Const

/* Private function prototypes -----------------------------------------------*/

/***********************************************************************************
 * @brief 
 * ex:
 * @par  
 * None
 * @retval 
 **********************************************************************************/
void GpioExit_Set(drv_gpioexit_t *this, uint8_t sw)
{
    if(sw){
        this->private.exit.EXTI_LineCmd = ENABLE;
    }
    else{
        this->private.exit.EXTI_LineCmd = DISABLE;
    }

    EXTI_Init(&this->private.exit);
}

/***********************************************************************************
 * @brief 
 * ex:
 * @par  
 * None
 * @retval 
 **********************************************************************************/
uint8_t GpioExit_Read(drv_gpioexit_t *this)
{
    if (this == NULL)
        return 0;
    
    return this->private.exit_io.Read(&this->private.exit_io);
}

/***********************************************************************************
 * @brief 
 * ex:
 * @par  
 * None
 * @retval 
 **********************************************************************************/
int Drv_GpioExit_Init(drv_gpioexit_t *this)
{   
    if(strlen(this->PIN) > 3 || strlen(this->PIN) < 2){
        return -1;
    }
    if(this->PIN[0] < 'A' || this->PIN[0] > 'G'){
        return -1;
    }
    
    uint8_t group_id    = this->PIN[0] - 'A';
    uint8_t pin_id      = atoi(&this->PIN[1]);
    
    if(group_id > (sizeof(exit_group) / sizeof(uint8_t) - 1)){
        return -1;
    }
    if(pin_id > (sizeof(exit_gpio) / sizeof(uint32_t) - 1)){
        return -1;
    }

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
    	//soft cs io config
	this->private.exit_io.PIN 			= this->PIN;
	this->private.exit_io.MODE			= this->MODE;
	this->private.exit_io.INIT_LEVEL 	= HIGHT_LEVEL;
	if(Drv_Gpio_Init(&this->private.exit_io) < 0){
		return -1;
	}
    /* Connect EXTI Line to INT Pin */
    SYSCFG_EXTILineConfig(exit_group[group_id], exit_gpio[pin_id]);
    
    /* Configure EXTI line */
    this->private.exit.EXTI_Line = exit_line[pin_id];
    this->private.exit.EXTI_Mode = EXTI_Mode_Interrupt;
    
    if(this->trigger == rising){
        this->private.exit.EXTI_Trigger = EXTI_Trigger_Rising;
    }
    else if(this->trigger == falling){
        this->private.exit.EXTI_Trigger = EXTI_Trigger_Falling;
    }
    else if(this->trigger == rising_falling){
        this->private.exit.EXTI_Trigger = EXTI_Trigger_Rising_Falling;
    }

    this->private.exit.EXTI_LineCmd = DISABLE;
    EXTI_Init(&this->private.exit);

    callback[pin_id]    = this->callback;
    this->Set           = GpioExit_Set;
    this->Read          = GpioExit_Read;

    uint8_t irqn;
    if(pin_id <= 4){
        irqn = exit_irqn[pin_id];
    }
    else if(pin_id <= 9){
        irqn = exit_irqn[5];
    }
    else{
        irqn = exit_irqn[6];
    }
    NVIC_InitTypeDef NVIC_InitStructure;
    NVIC_InitStructure.NVIC_IRQChannel = irqn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = this->PreempPriority;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
    
    return 0;
}

/***********************************************************************************
 * @brief 
 * ex:
 * @par  
 * None
 * @par 
 * None
 * @retval 
 **********************************************************************************/
#define  EXTI_IRQHandler(id)                            \
void EXTI##id##_IRQHandler(void)                        \
{                                                       \
    if (EXTI_GetITStatus(exit_line[id]) != RESET){      \
        callback[id]();                                 \
        EXTI_ClearITPendingBit(exit_line[id]);          \
    }                                                   \
}                                                       \

EXTI_IRQHandler(0);
EXTI_IRQHandler(1);
EXTI_IRQHandler(2);
EXTI_IRQHandler(3);
EXTI_IRQHandler(4);
//void EXTI0_IRQHandler(void)                        
//{                                                       
//    if (EXTI_GetITStatus(exit_line[0]) != RESET){  
//		
//        callback[0]();                                 
//        EXTI_ClearITPendingBit(exit_line[0]);          
//    }                                                   
//}  

//void EXTI1_IRQHandler(void)                        
//{                                                       
//    if (EXTI_GetITStatus(exit_line[1]) != RESET){  
//		
//        callback[1]();                                 
//        EXTI_ClearITPendingBit(exit_line[1]);          
//    }                                                   
//} 

//EXTI_IRQHandler(0);
//EXTI_IRQHandler(1);
//EXTI_IRQHandler(2);
//EXTI_IRQHandler(3);
//EXTI_IRQHandler(4);

/***********************************************************************************
 * @brief 
 * ex:
 * @par  
 * None
 * @par 
 * None
 * @retval 
 **********************************************************************************/
void EXTI9_5_IRQHandler(void)                        
{   
    uint8_t id;
    
    for(id=5; id<=9; id++){
        if (EXTI_GetITStatus(exit_line[id]) != RESET){
            if(callback[id] != NULL){
                callback[id](); 
            }                                
            EXTI_ClearITPendingBit(exit_line[id]);          
        }         
    }                                                  
}  

/***********************************************************************************
 * @brief 
 * ex:
 * @par  
 * None
 * @par 
 * None
 * @retval 
 **********************************************************************************/
void EXTI15_10_IRQHandler(void)                        
{   
    uint8_t id;
    
    for(id=10; id<=15; id++){
        if (EXTI_GetITStatus(exit_line[id]) != RESET){
            if(callback[id] != NULL){
                callback[id](); 
            }                                
            EXTI_ClearITPendingBit(exit_line[id]);          
        }         
    }                                                  
}


